import time
import random

# define the type of the animate
animateType = [(0, [" ", "><('>", "><>"]), (0, [".", ".!|.|!.", ".!|.|!."]),
               (0, ["_", "_.--._", "_.-*-._"]),
               (0, ["-", "\\(^o^)/", "/(-.-)\\"]), (0, ["/", "2", "B"]),
               (0, ["-", ">o<", "<->"]), (1, [" ", "^[o_o]^", "*[-_-]*"]),
               (1, [" ", "(*' v')", "('v '*)"]),
               (1, [" ", "~~(ToT)", "(ToT)~~"]),
               (1, [" ", "(๑´ڡ`๑)", "(๑´ڡ`๑)"]),
               (1, [" ", "( `(00)`)", "(`(00)` )"]),
               (1, [" ", "'^( )^'", "'^( )^'"]), (1, [" ", "(@.@)", "(-.-)"]),
               (2, [" ", "><('>", "<')><"]), (2, [" ", ">----<>", "<>----<"]),
               (2, ["_", "^^ ^", "^ ^^"])]


class animate:

    def __init__(self, len1=25, len2=12):
        """Animate

        Args:
            ty (_type_): type of the animate, 
            s (list, optional): animate String. Defaults to [" ", "><('>", "<')><"].
            len1 (int, optional): _description_. Defaults to 25.
            len2 (int, optional): _description_. Defaults to 12.
        """
        ty = random.randint(0, len(animateType) - 1)
        #part1
        self.len1 = len1
        #part2
        self.type, self.s = animateType[ty]
        self.len2 = len2
        self.reset()

    def reset(self):
        self.zipstartT = time.perf_counter()
        #part1
        self.loca = 0
        self.dire1 = 1
        #part2
        self.i = 0
        self.trig = random.randint(len(self.s) + 4,
                                   self.len2)  #trigger for mode1
        if self.type == 0:
            self.dire2 = [1]
            self.buf = [["", ""]]
        elif self.type == 1:
            self.dire2 = [1]
            self.buf = [[self.s[1], ""]]
        elif self.type == 2:
            self.dire2 = [1, -1]
            self.buf = [[self.s[1], ""], ["", ""]]
        self.bb = len(self.dire2) * [self.s[0] * self.len2]

    def next1(self, progress) -> str:
        if progress == -1: return ""
        prog = int(progress / 100 * self.len1)
        a = '█' * prog + " " * (self.len1 - prog)
        a = a[0:self.loca] + "-><"[self.dire1] + a[self.loca + 1:]
        if self.loca + self.dire1 >= self.len1 or self.loca + self.dire1 < prog:
            self.dire1 *= -1
        else:
            self.loca += self.dire1
        return "|" + a

    def _judge(self):
        if self.type == 0:
            if self.i % self.trig == 0:
                if random.randint(0, 1) == 0:
                    self.buf[0][0] = self.s[1]
                else:
                    self.buf[0][0] = self.s[2]
                self.i = 0
                self.trig = random.randint(
                    max(len(self.s[1]), len(self.s[2])) + 4, self.len2)
        elif self.type == 1:
            if self.i >= self.len2 and (self.i - self.len2) % (
                    self.len2 - len(self.s[1])) == 0:
                if self.dire2[0] == 1:
                    self.bb = [
                        self.s[0] * (self.len2 - len(self.s[2])) + self.s[2]
                    ]
                else:
                    self.bb = [
                        self.s[1] + self.s[0] * (self.len2 - len(self.s[1]))
                    ]
                self.dire2[0] *= -1
        elif self.type == 2:
            if (self.i - self.len2) % (2 * self.len2) == 0:
                self.buf[1][1] = self.s[2]
            elif (self.i - self.len2) % (2 * self.len2) == self.len2:
                self.buf[0][0] = self.s[1]

    def next2(self) -> str:
        self._judge()
        b = self.s[0] * self.len2
        for j, d in enumerate(self.dire2):
            if d == 1:
                self.bb[j] = (self.s[0] if self.buf[j][0] == "" else
                              self.buf[j][0][len(self.buf[j][0]) -
                                             1]) + self.bb[j][0:-1]
                self.buf[j][0] = self.buf[j][0][:-1]
            elif d == -1:
                self.bb[j] = self.bb[j][1:] + (self.s[0] if self.buf[j][1]
                                               == "" else self.buf[j][1][0])
                self.buf[j][1] = self.buf[j][1][1:]
            for k in range(self.len2):
                b = b[0:k] + (self.bb[j][k] if self.bb[j][k] != self.s[0] else
                              b[k]) + b[k + 1:]
        self.i += 1
        return "|" + b

    def timetake(self):
        timing = time.perf_counter() - self.zipstartT
        timetake = f"<{int(timing//3600):02d}:{int(timing% 3600//60):02d}:{int(timing % 60):02d}>"
        return timetake


if __name__ == "__main__":
    ani = animate(25, 12)
    for i in range(100):
        print(ani.timetake() + ani.next1(i) + ani.next2() + "|", end="\r")
        time.sleep(0.15)
